package com.jzo2o.orders.manager.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.AddressBookApi;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.api.foundations.ServeApi;
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
import com.jzo2o.api.market.CouponApi;
import com.jzo2o.api.market.dto.request.CouponUseReqDTO;
import com.jzo2o.api.market.dto.response.AvailableCouponsResDTO;
import com.jzo2o.api.market.dto.response.CouponUseResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.utils.DateUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.orders.base.constants.RedisConstants;
import com.jzo2o.orders.base.mapper.OrdersMapper;
import com.jzo2o.orders.base.model.domain.Orders;
import com.jzo2o.orders.manager.model.dto.request.PlaceOrderReqDTO;
import com.jzo2o.orders.manager.model.dto.response.PlaceOrderResDTO;
import com.jzo2o.orders.manager.service.IOrdersCreateService;
import com.jzo2o.redis.annotations.Lock;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 下单服务类
 * </p>
 *
 * @author itcast
 * @since 2023-07-10
 */
@Slf4j
@Service
public class OrdersCreateServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersCreateService {

    @Autowired
    private CouponApi couponApi;

    @Autowired
    private ServeApi serveApi;

    @Autowired
    private IOrdersCreateService owner;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AddressBookApi addressBookApi;

    @Override
    public List<AvailableCouponsResDTO> getAvailableCoupons(Long serveId, Integer purNum) {
        // 1.获取服务
        ServeAggregationResDTO serveResDTO = serveApi.findById(serveId);
        if (serveResDTO == null || serveResDTO.getSaleStatus() != 2) {
            throw new ForbiddenOperationException("服务不可用");
        }

        // 2.计算订单总金额
        BigDecimal totalAmount = serveResDTO.getPrice().multiply(new BigDecimal(purNum));

        // 3.获取可用优惠券,并返回优惠券列表
        List<AvailableCouponsResDTO> available = couponApi.getAvailable(totalAmount);
        return available;
    }

    //下单时使用优惠券
    @GlobalTransactional
    @Override
    public void saveOrdersWithCoupon(Orders orders, Long couponId) {
        //1. 调用优惠券微服务核销优惠券
        CouponUseReqDTO couponUseReqDTO = new CouponUseReqDTO();
        couponUseReqDTO.setId(couponId);//优惠券id
        couponUseReqDTO.setOrdersId(orders.getId());//订单id
        couponUseReqDTO.setTotalAmount(orders.getTotalAmount());//总金额
        //调用优惠券服务使用接口
        CouponUseResDTO couponUseResDTO = couponApi.use(couponUseReqDTO);

        //2. 修改订单的优惠金额和实付金额
        BigDecimal discountAmount = couponUseResDTO.getDiscountAmount();
        orders.setDiscountAmount(discountAmount);//优惠金额
        orders.setRealPayAmount(orders.getTotalAmount().subtract(discountAmount));//实付金额

        //3. 创建订单
        this.save(orders);
    }


    //todo 重点方法要复习
    /**
     * 下单（创建订单，需要使用分布式锁防止客户重复下单）
     * @param placeOrderReqDTO
     * @return
     */
    @Override
    public PlaceOrderResDTO place(PlaceOrderReqDTO placeOrderReqDTO) {
        Long userId = UserContext.currentUserId();
        return owner.place(userId, placeOrderReqDTO);
    }
    @Lock(formatter = "ORDERS:CREATE:LOCK:#{userId}:#{placeOrderReqDTO.serveId}", time = 30,waitTime = 1,unlock = false)
    public PlaceOrderResDTO place(Long userId,PlaceOrderReqDTO placeOrderReqDTO) {
        //创建订单
        Orders orders = new Orders();
        //封装参数
        Long serveId = placeOrderReqDTO.getServeId();
        orders.setId(generateOrdersId());
        orders.setUserId(UserContext.currentUserId());
        orders.setServeId(placeOrderReqDTO.getServeId());
        //调用serve远程调用
        ServeAggregationResDTO serveAggregationResDTO = serveApi.findById(serveId);
        orders.setServeTypeId(serveAggregationResDTO.getServeTypeId());
        orders.setServeTypeName(serveAggregationResDTO.getServeTypeName());
        orders.setServeItemId(serveAggregationResDTO.getId());
        orders.setServeItemName(serveAggregationResDTO.getServeItemName());
        orders.setServeItemImg(serveAggregationResDTO.getServeItemImg());
        BigDecimal price = serveAggregationResDTO.getPrice();
        orders.setPrice(price);
        orders.setUnit(serveAggregationResDTO.getUnit());
        orders.setCityCode(serveAggregationResDTO.getCityCode());
        //非远程调用
        orders.setOrdersStatus(0);
        orders.setPayStatus(2);
        orders.setPurNum(placeOrderReqDTO.getPurNum());
        orders.setTotalAmount(price.multiply(new BigDecimal(placeOrderReqDTO.getPurNum())));
        // todo 优惠金额实际支付金额暂无
        /*orders.setRealPayAmount(orders.getTotalAmount());
        orders.setDiscountAmount(BigDecimal.ZERO);*/

        //远程客户中心查询详细地址
        AddressBookResDTO addressBookResDTO = addressBookApi.detail(placeOrderReqDTO.getAddressBookId());
        orders.setServeAddress(addressBookResDTO.getAddress());
        orders.setContactsPhone(addressBookResDTO.getPhone());
        orders.setContactsName(addressBookResDTO.getName());
        orders.setLon(addressBookResDTO.getLon());
        orders.setLat(addressBookResDTO.getLat());

        orders.setServeStartTime(placeOrderReqDTO.getServeStartTime());
        orders.setDisplay(1);
        orders.setSortBy(DateUtils.toEpochMilli(placeOrderReqDTO.getServeStartTime())+ orders.getId()%100000);
        //只需要在这一行加事务
        if(ObjectUtils.isNull(placeOrderReqDTO.getCouponId())){
            //为使用优惠券
            owner.saveOrders(orders);
        }else {
            //使用优惠券
            owner.saveOrdersWithCoupon(orders,placeOrderReqDTO.getCouponId());
        }


        //返回订单id值（订单id是自己生成的）
        return new PlaceOrderResDTO(orders.getId());
    }


    @Override
    public void saveOrders(Orders orders) {
        //baseMapper.insert(orders);
        //这种方式会自动填充时间等字段
        this.save( orders);
    }

    //生成订单id-与订单支付方法配合使用
    private Long generateOrdersId() {
        //1. 2位年+2位月+2位日
        Long yyMMdd = DateUtils.getFormatDate(LocalDateTime.now(), "yyMMdd");

        //2. 自增数字  1 2
        Long num = redisTemplate.opsForValue().increment(RedisConstants.Lock.ORDERS_SHARD_KEY_ID_GENERATOR, 1);//1 代表的是每次增长量为1

        //3. 组装返回
        return yyMMdd * 10000000000000L + num;

    }
}
